From 1f63d5c05ba117e0158c02d5bc79fa1f38f8ce85 Mon Sep 17 00:00:00 2001
From: xue <>
Date: Thu, 27 Apr 2006 13:13:17 +0000
Subject: merge from 3.0 branch till 978.

---
 framework/Web/Javascripts/TJavaScript.php       |  42 +-
 framework/Web/Javascripts/js/prado.js           |  12 +-
 framework/Web/Javascripts/js/validator.js       | 110 ++--
 framework/Web/Javascripts/prado/form.js         |   2 +-
 framework/Web/Javascripts/prado/prado.js        |  16 +-
 framework/Web/Javascripts/prado/validation.js   | 767 ------------------------
 framework/Web/Javascripts/prado/validation3.js  | 154 ++---
 framework/Web/Javascripts/prado/validators.js   | 222 -------
 framework/Web/UI/WebControls/TBaseValidator.php | 111 ++++
 framework/Web/UI/WebControls/TClientScript.php  |  75 +++
 framework/Web/UI/WebControls/TLiteral.php       |   2 +-
 11 files changed, 381 insertions(+), 1132 deletions(-)
 delete mode 100644 framework/Web/Javascripts/prado/validation.js
 delete mode 100644 framework/Web/Javascripts/prado/validators.js
 create mode 100644 framework/Web/UI/WebControls/TClientScript.php

(limited to 'framework')

diff --git a/framework/Web/Javascripts/TJavaScript.php b/framework/Web/Javascripts/TJavaScript.php
index a3848201..75fc2438 100644
--- a/framework/Web/Javascripts/TJavaScript.php
+++ b/framework/Web/Javascripts/TJavaScript.php
@@ -84,6 +84,26 @@ class TJavaScript
 		else
 			return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\'));
 	}
+	
+	/**
+	 * @return string considers the string as raw javascript function code
+	 */
+	public static function quoteFunction($js)
+	{
+		if(self::isFunction($js))
+			return $js;
+		else
+			return 'javascript:'.$js; 
+	}
+	
+	/**
+	 * @return boolean true if string is raw javascript function code, i.e., if
+	 * the string begins with <tt>javascript:</tt>
+	 */
+	public static function isFunction($js)
+	{
+		return preg_match('/^\s*javascript:/', $js);
+	}
 
 	/**
 	 * Encodes a PHP variable into javascript representation.
@@ -96,16 +116,12 @@ class TJavaScript
 	 * //expects the following javascript code
 	 * // {'onLoading':'doit','onComplete':'more'}
 	 * </code>
-	 * 
-	 * To pass raw javascript statements start strings with 
-	 * <tt>javascript:</tt>. E.g. 
-	 * <code>
-	 * $options['onLoading'] = "javascript:function(){ alert('hello'); }";
-	 * //outputs {'onLoading':function(){ alert('hello'); }}
-	 * </code>
 	 *
-	 * For higher complexity data structures use {@link jsonEncode} and {@link
-	 * jsonDecode} to serialize and unserialize.
+	 * For higher complexity data structures use {@link jsonEncode} and {@link jsonDecode}
+	 * to serialize and unserialize.
+	 * 
+	 * Note: strings begining with <tt>javascript:</tt> will be considered as
+	 * raw javascript code and no encoding of that string will be enforced. 
 	 *
 	 * @param mixed PHP variable to be encoded
 	 * @param boolean whether the output is a map or a list.
@@ -122,9 +138,11 @@ class TJavaScript
 				if(($first==='[' && $last===']') || ($first==='{' && $last==='}'))
 					return $value;
 			}
-			else if(strpos($value, 'javascript:')===0)
-				return substr($value,11);
-			return "'".self::quoteString($value)."'";
+			// if string begins with javascript: return the raw string minus the prefix
+			if(self::isFunction($value))
+				return preg_replace('/^\s*javascript:/', '', $value);
+			else
+				return "'".self::quoteString($value)."'";
 		}
 		else if(is_bool($value))
 			return $value?'true':'false';
diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js
index c7145188..394d5eeb 100644
--- a/framework/Web/Javascripts/js/prado.js
+++ b/framework/Web/Javascripts/js/prado.js
@@ -1803,9 +1803,9 @@ var newdate=new Date(year,month-1,date, 0, 0, 0);
 return newdate;
 }
 });
-var Prado = 
-{ 
-Version: '3.0a',
+var Prado =
+{
+Version: '3.0.0',
 Browser : function()
 {
 var info = { Version : "1.0" };
@@ -1830,11 +1830,11 @@ info.opera7 = ( ( info.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( info
 info.operaOld = info.opera && !info.opera7;
 return info;
 },
-ImportCss : function(doc, css_file) 
+ImportCss : function(doc, css_file)
 {
 if (Prado.Browser().ie)
 var styleSheet = doc.createStyleSheet(css_file);
-else 
+else
 {
 var elm = doc.createElement("link");
 elm.rel = "stylesheet";
@@ -1850,7 +1850,7 @@ var form = $(options['FormID']);
 var canSubmit = true;
 if(options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
 {
-if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup']))
+if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup'], $(options['ID'])))
 return Event.stop(event);
 }
 if(options['PostBackUrl'] && options['PostBackUrl'].length > 0)
diff --git a/framework/Web/Javascripts/js/validator.js b/framework/Web/Javascripts/js/validator.js
index 8659d2e9..5e23df50 100644
--- a/framework/Web/Javascripts/js/validator.js
+++ b/framework/Web/Javascripts/js/validator.js
@@ -3,11 +3,11 @@ Prado.Validation =Class.create();
 Object.extend(Prado.Validation,
 {
 managers : {},
-validate : function(formID, groupID)
+validate : function(formID, groupID, invoker)
 {
 if(this.managers[formID])
 {
-return this.managers[formID].validate(groupID);
+return this.managers[formID].validate(groupID, invoker);
 }
 else
 {
@@ -49,14 +49,14 @@ initialize : function(options)
 this.options = options;
 Prado.Validation.managers[options.FormID] = this;
 },
-validate : function(group)
+validate : function(group, invoker)
 {
 if(group)
-return this._validateGroup(group);
+return this._validateGroup(group, invoker);
 else
-return this._validateNonGroup();
+return this._validateNonGroup(invoker);
 },
-_validateGroup: function(groupID)
+_validateGroup: function(groupID, invoker)
 {
 var valid = true;
 if(this.groups.include(groupID))
@@ -64,7 +64,7 @@ if(this.groups.include(groupID))
 this.validators.each(function(validator)
 {
 if(validator.group == groupID)
-valid = valid & validator.validate();
+valid = valid & validator.validate(invoker);
 else
 validator.hide();
 });
@@ -72,13 +72,13 @@ validator.hide();
 this.updateSummary(groupID, true);
 return valid;
 },
-_validateNonGroup : function()
+_validateNonGroup : function(invoker)
 {
 var valid = true;
 this.validators.each(function(validator)
 {
 if(!validator.group)
-valid = valid & validator.validate();
+valid = valid & validator.validate(invoker);
 else
 validator.hide();
 });
@@ -275,11 +275,9 @@ options : {},
 _isObserving : {},
 group : null,
 manager : null,
+message : null,
 initialize : function(options)
 {
-options.OnValidate = options.OnValidate || Prototype.emptyFunction;
-options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
-options.OnError = options.OnError || Prototype.emptyFunction;
 this.options = options;
 this.control = $(options.ControlToValidate);
 this.message = $(options.ID);
@@ -321,16 +319,34 @@ this.isValid = true;
 this.updateControl();
 this.visible = false;
 },
-validate : function()
+validate : function(invoker)
 {
+if(typeof(this.options.OnValidate) == "function")
+this.options.OnValidate(this, invoker);
 if(this.enabled)
 this.isValid = this.evaluateIsValid();
-this.options.OnValidate(this);
-this.updateControl();
 if(this.isValid)
-this.options.OnSuccess(this);
+{
+if(typeof(this.options.OnSuccess) == "function")
+{
+this.visible = true;
+this.updateControlCssClass(this.control, this.isValid);
+this.options.OnSuccess(this, invoker);
+}
+else
+this.updateControl();
+}
 else
-this.options.OnError(this);
+{
+if(typeof(this.options.OnError) == "function")
+{
+this.visible = true;
+this.updateControlCssClass(this.control, this.isValid);
+this.options.OnError(this, invoker);
+}
+else
+this.updateControl();
+}
 this.observeChanges(this.control);
 return this.isValid;
 },
@@ -353,7 +369,7 @@ validator.manager.updateSummary(validator.group);
 this._isObserving[control.id+this.options.ID] = true;
 }
 },
-_trim : function(value)
+trim : function(value)
 {
 return typeof(value) == "string" ? value.trim() : "";
 },
@@ -393,20 +409,20 @@ getValidationValue : function(control)
  {
  case 'TDatePicker':
  if(control.type == "text")
- return this._trim($F(control));
+ return this.trim($F(control));
  else
  {
- this._observeDatePickerChanges();
+ this.observeDatePickerChanges();
 return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime();
  }
  default:
- if(this._isListControlType())
- return this._getFirstSelectedListValue(); 
+ if(this.isListControlType())
+ return this.getFirstSelectedListValue(); 
  else
- return this._trim($F(control));
+ return this.trim($F(control));
  }
  },
-_observeDatePickerChanges : function()
+observeDatePickerChanges : function()
  {
  if(Prado.Browser().ie)
  {
@@ -416,11 +432,11 @@ this.observeChanges(DatePicker.getMonthListControl(this.control));
 this.observeChanges(DatePicker.getYearListControl(this.control));
  }
  },
-_getSelectedValuesAndChecks : function(elements, initialValue)
+getSelectedValuesAndChecks : function(elements, initialValue)
 {
 var checked = 0;
 var values = [];
-var isSelected = this._isCheckBoxType(elements[0]) ? 'checked' : 'selected';
+var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
 elements.each(function(element)
 {
 if(element[isSelected] && element.value != initialValue)
@@ -431,7 +447,7 @@ values.push(element.value);
 });
 return {'checks' : checked, 'values' : values};
 }, 
-_getListElements : function()
+getListElements : function()
 {
 switch(this.options.ControlType)
 {
@@ -440,7 +456,7 @@ var elements = [];
 for(var i = 0; i < this.options.TotalItems; i++)
 {
 var element = $(this.options.ControlToValidate+"_"+i);
-if(this._isCheckBoxType(element))
+if(this.isCheckBoxType(element))
 elements.push(element);
 }
 return elements;
@@ -457,7 +473,7 @@ default:
 return [];
 }
 },
-_isCheckBoxType : function(element)
+isCheckBoxType : function(element)
 {
 if(element && element.type)
 {
@@ -466,18 +482,18 @@ return type == "checkbox" || type == "radio";
 }
 return false;
 },
-_isListControlType : function()
+isListControlType : function()
 {
 var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
 return list.include(this.options.ControlType);
 },
-_getFirstSelectedListValue : function()
+getFirstSelectedListValue : function()
 {
 var initial = "";
 if(typeof(this.options.InitialValue) != "undefined")
 initial = this.options.InitialValue;
-var elements = this._getListElements();
-var selection = this._getSelectedValuesAndChecks(elements, initial);
+var elements = this.getListElements();
+var selection = this.getSelectedValuesAndChecks(elements, initial);
 return selection.values.length > 0 ? selection.values[0] : initial;
 }
 }
@@ -493,7 +509,7 @@ return true;
 else
 {
 var a = this.getValidationValue();
-var b = this._trim(this.options.InitialValue);
+var b = this.trim(this.options.InitialValue);
 return(a != b);
 }
 }
@@ -595,16 +611,16 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
 {
 evaluateIsValid : function()
 {
-var elements = this._getListElements();
+var elements = this.getListElements();
 if(elements && elements.length <= 0)
 return true;
 this.observeListElements(elements);
-var selection = this._getSelectedValuesAndChecks(elements);
+var selection = this.getSelectedValuesAndChecks(elements);
 return this.isValidList(selection.checks, selection.values);
 },
 observeListElements : function(elements)
  {
-if(Prado.Browser().ie && this._isCheckBoxType(elements[0]))
+if(Prado.Browser().ie && this.isCheckBoxType(elements[0]))
 {
 var validator = this;
 elements.each(function(element)
@@ -640,13 +656,13 @@ required = this.options.Required.split(/,\s*/);
 return required;
 }
 });
-Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
-evaluateIsValid : function()
-{
-var value = this.getValidationValue();
-if(value.length <= 0)
-return true;
-return this.convert(this.options.DataType, value) != null;
-}
-});
+Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator, 
+{ 
+evaluateIsValid : function() 
+{ 
+var value = this.getValidationValue(); 
+if(value.length <= 0) 
+return true; 
+return this.convert(this.options.DataType, value) != null; 
+} 
+}); 
diff --git a/framework/Web/Javascripts/prado/form.js b/framework/Web/Javascripts/prado/form.js
index 2beb945b..aec9395d 100644
--- a/framework/Web/Javascripts/prado/form.js
+++ b/framework/Web/Javascripts/prado/form.js
@@ -107,7 +107,7 @@ Prado.PostBack = function(event,options)
 
 	if(options['CausesValidation'] && typeof(Prado.Validation) != "undefined")
 	{
-		if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup']))
+		if(!Prado.Validation.validate(options['FormID'], options['ValidationGroup'], $(options['ID'])))
 			return Event.stop(event);
 	}
 
diff --git a/framework/Web/Javascripts/prado/prado.js b/framework/Web/Javascripts/prado/prado.js
index e63c2718..ad51e2f7 100644
--- a/framework/Web/Javascripts/prado/prado.js
+++ b/framework/Web/Javascripts/prado/prado.js
@@ -1,8 +1,8 @@
 
-var Prado = 
-{ 
-	Version: '3.0a',
-	
+var Prado =
+{
+	Version: '3.0.0',
+
 	/**
 	 * Returns browser information. Example
 	 * <code>
@@ -36,12 +36,12 @@ var Prado =
 		info.operaOld = info.opera && !info.opera7;
 		return info;
 	},
-	
-	ImportCss : function(doc, css_file) 
+
+	ImportCss : function(doc, css_file)
 	{
 		if (Prado.Browser().ie)
 			var styleSheet = doc.createStyleSheet(css_file);
-		else 
+		else
 		{
 			var elm = doc.createElement("link");
 
@@ -51,5 +51,5 @@ var Prado =
 			if (headArr = doc.getElementsByTagName("head"))
 				headArr[0].appendChild(elm);
 		}
-	}	
+	}
 };
diff --git a/framework/Web/Javascripts/prado/validation.js b/framework/Web/Javascripts/prado/validation.js
deleted file mode 100644
index 454f53f0..00000000
--- a/framework/Web/Javascripts/prado/validation.js
+++ /dev/null
@@ -1,767 +0,0 @@
-
-/**
- * Prado client-side javascript validation class.
- */
-Prado.Validation = Class.create();
-
-/**
- * Utilities for validation. Static class.
- */
-Prado.Validation.Util = Class.create();
-
-/** 
- * Convert a string into integer, returns null if not integer.
- * @param {string} the string to convert to integer
- * @type {integer|null} null if string does not represent an integer.
- */
-Prado.Validation.Util.toInteger = function(value)
-{
-	var exp = /^\s*[-\+]?\d+\s*$/;
-	if (value.match(exp) == null)
-		return null;
-	var num = parseInt(value, 10);
-	return (isNaN(num) ? null : num);
-}
-
-/** 
- * Convert a string into a double/float value. <b>Internationalization 
- * is not supported</b>
- * @param {string} the string to convert to double/float
- * @param {string} the decimal character
- * @return {float|null} null if string does not represent a float value
- */
-Prado.Validation.Util.toDouble = function(value, decimalchar)
-{
-	decimalchar = undef(decimalchar) ? "." : decimalchar;
-	var exp = new RegExp("^\\s*([-\\+])?(\\d+)?(\\" + decimalchar + "(\\d+))?\\s*$");
-    var m = value.match(exp);
-    if (m == null)	
-		return null;
-	var cleanInput = m[1] + (m[2].length>0 ? m[2] : "0") + "." + m[4];
-    var num = parseFloat(cleanInput);
-    return (isNaN(num) ? null : num);
-}
-
-/**
- * Convert strings that represent a currency value (e.g. a float with grouping 
- * characters) to float. E.g. "10,000.50" will become "10000.50". The number 
- * of dicimal digits, grouping and decimal characters can be specified.
- * <i>The currency input format is <b>very</b> strict, null will be returned if
- * the pattern does not match</i>.
- * @param {string} the currency value
- * @param {string} the grouping character, default is ","
- * @param {int} number of decimal digits
- * @param {string} the decimal character, default is "."
- * @type {float|null} the currency value as float.
- */
-Prado.Validation.Util.toCurrency = function(value, groupchar, digits, decimalchar)
-{
-	groupchar = undef(groupchar) ? "," : groupchar;
-	decimalchar = undef(decimalchar) ? "." : decimalchar;
-	digits = undef(digits) ? 2 : digits;
-
-	var exp = new RegExp("^\\s*([-\\+])?(((\\d+)\\" + groupchar + ")*)(\\d+)"
-		+ ((digits > 0) ? "(\\" + decimalchar + "(\\d{1," + digits + "}))?" : "")
-        + "\\s*$");
-	var m = value.match(exp);
-	if (m == null)
-		return null;
-	var intermed = m[2] + m[5] ;
-    var cleanInput = m[1] + intermed.replace(
-			new RegExp("(\\" + groupchar + ")", "g"), "") 
-							+ ((digits > 0) ? "." + m[7] : "");
-	var num = parseFloat(cleanInput);
-	return (isNaN(num) ? null : num);
-}
-
-/**
- * Get the date from string using the prodivided date format string.
- * The format notations are
- * # day -- %d or %e
- * # month -- %m
- * # year -- %y or %Y
- * # hour -- %H, %I, %k, or %l
- * # minutes -- %M
- * # P.M. -- %p or %P
- * @param {string} the formatted date string
- * @param {string} the date format
- * @type {Date} the date represented in the string
- */
-Prado.Validation.Util.toDate = function(value, format)
-{
-	var y = 0;
-	var m = -1;
-	var d = 0;
-	var a = value.split(/\W+/);
-	var b = format.match(/%./g);
-	var i = 0, j = 0;
-	var hr = 0;
-	var min = 0;
-	for (i = 0; i < a.length; ++i) {
-		if (!a[i])
-			continue;
-		switch (b[i]) {
-		    case "%d":
-		    case "%e":
-			d = parseInt(a[i], 10);
-			break;
-
-		    case "%m":
-			m = parseInt(a[i], 10) - 1;
-			break;
-
-		    case "%Y":
-		    case "%y":
-			y = parseInt(a[i], 10);
-			(y < 100) && (y += (y > 29) ? 1900 : 2000);
-			break;
-
-		    case "%H":
-		    case "%I":
-		    case "%k":
-		    case "%l":
-			hr = parseInt(a[i], 10);
-			break;
-
-		    case "%P":
-		    case "%p":
-			if (/pm/i.test(a[i]) && hr < 12)
-				hr += 12;
-			break;
-
-		    case "%M":
-			min = parseInt(a[i], 10);
-			break;
-		}
-	}
-	if (y != 0 && m != -1 && d != 0)
-	{
-		var date = new Date(y, m, d, hr, min, 0);
-		return (isObject(date)
-				&& y == date.getFullYear() 
-				&& m == date.getMonth() 
-				&& d == date.getDate()) ? date.valueOf() : null;
-	}
-	return null;
-}
-
-/**
- * Trim the value, if the value is undefined, empty string is return.
- * @param {string} string to be trimmed.
- * @type {string} trimmed string.
- */
-Prado.Validation.trim = function(value)
-{
-	if(isString(value)) return value.trim();
-	return "";
-}
-
-/**
- * A delayed focus on a particular element
- * @param {element} element to apply focus()
- */
-Prado.Validation.Util.focus = function(element)
-{
-	var obj = $(element);
-	if(isObject(obj) && isdef(obj.focus))
-		setTimeout(function(){ obj.focus(); }, 100);
-	return false;
-}
-
-/**
- * List of validator instances.
- */
-Prado.Validation.validators = [];
-
-/**
- * List of forms.
- * @type {int}
- */
-Prado.Validation.forms = [];
-
-/**
- * List of summary controls.
- */
-Prado.Validation.summaries = [];
-
-/**
- * Validation groups.
- */
-Prado.Validation.groups = [];
-
-
-/**
- * Second type of grouping.
- */
-Prado.Validation.TargetGroups = {};
-
-
-/**
- * Current Target group.
- */
-Prado.Validation.CurrentTargetGroup = null;
-
-Prado.Validation.HasTargetGroup = false;
-
-/**
- * Targets that can cause validation.
- */
-Prado.Validation.ActiveTarget = null;
-
-
-/**
- * Determine if group validation is active.
- */
-Prado.Validation.IsGroupValidation = false;
-
-/**
- * Add a form for validation.
- * @param {string} form ID
- */
-Prado.Validation.AddForm = function(id)
-{
-	Prado.Validation.forms.push($(id));
-}
-
-/**
- * Add a target that causes validation. Only elements that have been added
- * can cause validation.
- * @param {string} target id
- */
-Prado.Validation.AddTarget = function(id, group)
-{
-	var target = $(id);	
-	Event.observe(target, "click", function()
-	{
-		Prado.Validation.ActiveTarget = target;
-		Prado.Validation.CurrentTargetGroup = Prado.Validation.TargetGroups[id];
-	});
-	if(group)
-	{
-		Prado.Validation.TargetGroups[id] = group;
-		Prado.Validation.HasTargetGroup = true;
-	}
-}
-
-Prado.Validation.SetActiveGroup = function(target, group)
-{
-	Prado.Validation.ActiveTarget = target;
-	Prado.Validation.CurrentTargetGroup = group;
-}
-
-/**
- * Associate a list of validators to a particular control element.
- * This essentially allows a set of validators to be grouped to a particular button.
- * @param {list} group array show have, {group : "id", target : "target button"}
- * @param {array} validator ids
- */
-Prado.Validation.AddGroup = function(group, validators)
-{
-	group.active = false; //default active status is false.
-	group.target = $(group.target);
-	group.validators = validators;
-	Prado.Validation.groups.push(group);
-
-	//update the active group when the button is clicked.
-	Event.observe(group.target, "click", Prado.Validation.UpdateActiveGroup);
-}
-
-/**
- * Update the active group, if call manually it will deactivate all groups.
- * @param {string}
- * @type {int}
- */
-Prado.Validation.UpdateActiveGroup = function(ev)
-{
-	var groups = Prado.Validation.groups;
-	for (var i = 0; i < groups.length; i++)
-	{
-		groups[i].active = (isdef(ev) && groups[i].target == Event.element(ev));
-	}
-	Prado.Validation.IsGroupValidation = isdef(ev);
-}
-
-/**
- * Determine if validation is sucessful. Iterate through the list 
- * of validator instances and call validate(). Only validators that
- * for a particular form are evaluated. Other validators will be disabled.
- * If performing group validation, only active validators are visible.
- * @param {element} the form for the controls to validate.
- * @type {boolean} true is all validators are valid, false otherwise.
- */
-Prado.Validation.IsValid = function(form)
-{
-	var valid = true;
-	var validators = Prado.Validation.validators;
-	
-	for(var i = 0; i < validators.length; i++)
-	{
-		//prevent validating multiple forms
-		validators[i].enabled = !validators[i].control || undef(validators[i].control.form) || validators[i].control.form == form;
-		//when group validation, only validators in the active group are visible.
-		validators[i].visible = Prado.Validation.IsGroupValidation ? validators[i].inActiveGroup() : true;
-
-		if(Prado.Validation.HasTargetGroup)
-			validators[i].enabled = Prado.Validation.CurrentTargetGroup == validators[i].group
-
-		valid &= validators[i].validate();
-	}
-
-	//show the summary including the alert box
-	Prado.Validation.ShowSummary(form);
-	//reset all the group active status to false
-	Prado.Validation.UpdateActiveGroup();
-
-	return valid;
-}
-
-/**
- * Base validator class. Supply a different validation function
- * to obtain a different validator. E.g. to use the RequiredFieldValidator
- * <code>new Prado.Validation(Prado.Validation.RequiredFieldValidator, options);</code>
- * or to use the CustomValidator, 
- * <code>new Prado.Validation(Prado.Validation.CustomValidator, options);</code>
- */
-Prado.Validation.prototype = 
-{
-	/**
-	 * Initialize the validator.
-	 * @param {function} the function to call to evaluate if 
-	 * the validator is valid
-	 * @param {string|element} the control ID or element
-	 * @param {array} the list of attributes for the validator
-	 */
-	initialize : function(validator, attr)
-	{
-		this.evaluateIsValid = validator;
-		this.attr = undef(attr) ? [] : attr;
-		this.message = $(attr.id);
-		this.control = $(attr.controltovalidate);
-		this.enabled = isdef(attr.enabled) ? attr.enabled : true;
-		this.visible = isdef(attr.visible) ? attr.visible : true;
-		this.group = isdef(attr.validationgroup) ? attr.validationgroup : null;
-		this.isValid = true;
-		Prado.Validation.validators.push(this);
-		if(this.evaluateIsValid)
-			this.evaluateIsValid.bind(this);
-	},
-
-	/**
-	 * Evaluate the validator only when visible and enabled.
-	 * @type {boolean} true if valid, false otherwise.
-	 */
-	validate : function()
-	{		
-		if(this.visible && this.enabled && this.evaluateIsValid)
-			this.isValid = this.evaluateIsValid();
-		else
-			this.isValid = true;
-		
-		this.observe(); //watch for changes to the control values
-		this.update(); //update the validation messages
-		return this.isValid;
-	},
-
-	/**
-	 * Hide or show the error messages for "Dynamic" displays.
-	 */
-	update : function()
-	{
-		if(this.attr.display == "Dynamic")
-			this.isValid ? Element.hide(this.message) : Element.show(this.message);
-		
-		if(this.message)
-			this.message.style.visibility = this.isValid ? "hidden" : "visible";
-
-		//update the control css class name
-		var className = this.attr.controlcssclass;
-		if(this.control && isString(className) && className.length>0)
-			Element.condClassName(this.control, className, !this.isValid);
-		Prado.Validation.ShowSummary();
-
-		var focus = this.attr.focusonerror;
-		var hasGroup = Prado.Validation.HasTargetGroup;
-		var inGroup = this.group == Prado.Validation.CurrentTargetGroup;
-
-		if(focus && (!hasGroup || (hasGroup && inGroup)))
-			Prado.Element.focus(this.attr.focuselementid);
-	},
-
-	/**
-	 * Change the validity of the validator, calls update().
-	 * @param {boolean} change the isValid state of the validator.
-	 */
-	setValid : function(valid)
-	{
-		this.isValid = valid;
-		this.update();
-	},
-
-	/**
-	 * Observe changes to the control values, add "onchange" event to the control once.
-	 */
-	observe : function()
-	{
-		if(undef(this.observing))
-		{
-			if(this.control && this.control.form)
-				Event.observe(this.control, "change", this.validate.bind(this));
-			this.observing = true;
-		}
-	},
-
-	/**
-	 * Convert the value of the control to a specific data type.
-	 * @param {string} the data type, "Integer", "Double", "Currency" or "Date".
-	 * @param {string} the value to convert, null to get the value from the control.
-	 * @type {mixed|null} the converted data value.
-	 */
-	convert : function(dataType, value)
-	{
-		if(undef(value))
-			value = Form.Element.getValue(this.control);
-		switch(dataType)
-		{
-			case "Integer":
-				return Prado.Validation.Util.toInteger(value);
-			case "Double" :
-			case "Float" :
-				return Prado.Validation.Util.toDouble(value, this.attr.decimalchar);
-			case "Currency" :
-				return Prado.Validation.Util.toCurrency(
-					value, this.attr.groupchar, this.attr.digits, this.attr.decimalchar);
-			case "Date":
-				return Prado.Validation.Util.toDate(value, this.attr.dateformat);			
-		}
-		return value.toString();
-	},
-
-	/**
-	 * Determine if the current validator is part of a active validation group.
-	 * @type {boolean} true if part of active validation group, false otherwise.
-	 */
-	inActiveGroup : function()
-	{
-		var groups = Prado.Validation.groups;
-		for (var i = 0; i < groups.length; i++)
-		{
-			if(groups[i].active && groups[i].validators.contains(this.attr.id))
-				return true;
-		}
-		return false;
-	}
-}
-
-/**
- * Validation summary class.
- */
-Prado.Validation.Summary = Class.create();
-Prado.Validation.Summary.prototype = 
-{
-	/**
-	 * Initialize a validation summary.
-	 * @param {array} summary options.
-	 */
-	initialize : function(attr)
-	{
-		this.attr = attr;
-		this.div = $(attr.id);
-		this.visible = false;
-		this.enabled = false;
-		this.group = isdef(attr.validationgroup) ? attr.validationgroup : null;
-		Prado.Validation.summaries.push(this);
-	},
-
-	/**
-	 * Show the validation summary.
-	 * @param {boolean} true to allow alert message
-	 */
-	show : function(warn)
-	{
-		var refresh = warn || this.attr.refresh == "1";
-		var messages = this.getMessages();	
-		if(messages.length <= 0 || !this.visible || !this.enabled) 
-		{
-			if(refresh)
-			{
-				if(this.attr.display == "None" || this.attr.display == "Dynamic")
-					Element.hide(this.div); 
-				else
-					this.div.style.visibility="hidden";
-			}
-			return;
-		}
-
-		if(Prado.Validation.HasTargetGroup)
-		{
-			if(Prado.Validation.CurrentTargetGroup != this.group)
-			{
-				if(refresh)
-				{
-					if(this.attr.display == "None" || this.attr.display == "Dynamic")
-						Element.hide(this.div); 
-					else
-						this.div.style.visibility="hidden";
-				}
-				return;
-			}
-		}
-		
-		if(this.attr.showsummary != "False" && refresh)
-		{
-			//Element.show(this.div);
-			this.div.style.display = "block";
-			this.div.style.visibility = "visible";
-			while(this.div.childNodes.length > 0)
-				this.div.removeChild(this.div.lastChild);
-			new Insertion.Bottom(this.div, this.formatSummary(messages));
-		}
-		
-		if(warn)
-			window.scrollTo(this.div.offsetLeft-20, this.div.offsetTop-20);
-	
-		var summary = this;
-		if(warn && this.attr.showmessagebox == "True" && refresh)
-			setTimeout(function(){alert(summary.formatMessageBox(messages));},20);
-	},
-
-	/**
-	 * Get a list of error messages from the validators.
-	 * @type {array} list of messages
-	 */
-	getMessages : function()
-	{
-		var validators = Prado.Validation.validators;
-		var messages = [];
-		for(var i = 0; i < validators.length; i++)
-		{			
-			if(validators[i].isValid == false
-				&& isString(validators[i].attr.errormessage)
-				&& validators[i].attr.errormessage.length > 0)
-			{
-					
-				messages.push(validators[i].attr.errormessage);
-			}
-		}
-		return messages;
-	},
-
-	/**
-	 * Return the format parameters for the summary.
-	 * @param {string} format type, "List", "SingleParagraph" or "BulletList"
-	 * @type {array} formatting parameters
-	 */
-	formats : function(type)
-	{
-		switch(type)
-		{
-			case "List":
-				return { header : "<br />", first : "", pre : "", post : "<br />", last : ""};
-			case "SingleParagraph":
-				return { header : " ", first : "", pre : "", post : " ", last : "<br />"};
-			case "BulletList":
-			default:
-				return { header : "", first : "<ul>", pre : "<li>", post : "</li>", last : "</ul>"};
-		}
-	},
-
-	/**
-	 * Format the message summary.
-	 * @param {array} list of error messages.
-	 * @type {string} formatted message
-	 */
-	formatSummary : function(messages)
-	{
-		var format = this.formats(this.attr.displaymode);
-		var output = isdef(this.attr.headertext) ? this.attr.headertext + format.header : "";
-		output += format.first;
-		for(var i = 0; i < messages.length; i++)
-			output += (messages[i].length>0) ? format.pre + messages[i] + format.post : "";
-		output += format.last;
-		return output;
-	},
-	/**
-	 * Format the message alert box.
-	 * @param {array} a list of error messages.
-	 * @type {string} format message for alert.
-	 */
-	formatMessageBox : function(messages)
-	{
-		var output = isdef(this.attr.headertext) ? this.attr.headertext + "\n" : "";
-		for(var i = 0; i < messages.length; i++)
-		{
-			switch(this.attr.displaymode)
-			{
-				case "List":
-					output += messages[i] + "\n";
-					break;
-				case "BulletList":
-                default:
-					output += "  - " + messages[i] + "\n";
-					break;
-				case "SingleParagraph":
-					output += messages[i] + " ";
-					break;
-			}
-		}
-		return output;
-	},
-
-	/**
-	 * Determine if this summary belongs to an active group.
-	 * @type {boolean} true if belongs to an active group.
-	 */
-	inActiveGroup : function()
-	{
-		var groups = Prado.Validation.groups;
-		for (var i = 0; i < groups.length; i++)
-		{
-			if(groups[i].active && groups[i].id == this.attr.group)
-				return true;
-		}
-		return false;
-	}
-}
-
-/**
- * Show the validation error message summary.
- * @param {element} the form that activated the summary call.
- */
-Prado.Validation.ShowSummary = function(form)
-{
-	var summary = Prado.Validation.summaries;
-	for(var i = 0; i < summary.length; i++)
-	{
-		if(isdef(form))
-		{			
-			if(Prado.Validation.IsGroupValidation)
-			{
-				summary[i].visible =  summary[i].inActiveGroup();
-			}
-			else 
-			{				
-				summary[i].visible = undef(summary[i].attr.group);
-			}
-
-			summary[i].enabled = $(summary[i].attr.form) == form;	
-		}
-		summary[i].show(form);
-	}
-}
-
-
-
-/**
- * When a form is try to submit, check the validators, submit
- * the form only when all validators are valid.
- * @param {event} form submit event.
- */
-Prado.Validation.OnSubmit = function(ev)
-{
-	//HTML text editor, tigger save first.
-	//alert(tinyMCE);
-	if(typeof tinyMCE != "undefined")
-		tinyMCE.triggerSave();
-
-	//no active target?
-	if(!Prado.Validation.ActiveTarget) return true;
-	var valid = Prado.Validation.IsValid(Event.element(ev) || ev);
-
-	//not valid? do not submit the form
-	if(Event.element(ev) && !valid)
-			Event.stop(ev);
-
-	//reset the target
-	Prado.Validation.ActiveTarget = null;
-	//Prado.Validation.CurrentTargetGroup = null;
-
-	return valid;
-}
-
-/**
- * During window onload event, attach onsubmit event for each of the
- * forms in Prado.Validation.forms.
- */
-Prado.Validation.OnLoad = function()
-{
-	Event.observe(Prado.Validation.forms,"submit", Prado.Validation.OnSubmit);
-}
-
-
-/**
- * Validate Validator Groups.
- * @param string ValidatorGroup
- * @return boolean true if valid, false otherwise
- */
-Prado.Validation.ValidateValidatorGroup = function(groupId)
-{
-	var groups = Prado.Validation.groups;
-	var group = null;
-	for(var i = 0; i < groups.length; i++)
-	{
-		if(groups[i].id == groupId)
-		{
-			group = groups[i];
-			Prado.Validation.groups[i].active = true;
-			Prado.Validation.CurrentTargetGroup = null;
-			Prado.Validation.IsGroupValidation = true;
-		}
-		else
-		{
-			Prado.Validation.groups[i].active = false;
-		}
-	}
-	if(group)
-	{
-		return Prado.Validation.IsValid(group.target.form);
-	}
-	return true;
-};
-
-/**
- * Validate ValidationGroup
- * @param string ValidationGroup
- * @return boolean true if valid, false otherwise.
- */
-Prado.Validation.ValidateValidationGroup= function(groupId)
-{
-	var groups = Prado.Validation.TargetGroups;
-	for(var id in groups)
-	{
-		if(groups[id] == groupId)
-		{
-			var target = $(id);
-			Prado.Validation.ActiveTarget = target;
-			Prado.Validation.CurrentTargetGroup = groupId;
-			Prado.Validation.IsGroupValidation = false;
-			return Prado.Validation.IsValid(target.form);
-		}
-	}
-
-	return true;
-};
-
-/**
- * Validate the page
- * @return boolean true if valid, false otherwise.
- */
-Prado.Validation.ValidateNonGroup= function(formId)
-{
-	if(Prado.Validation)
-	{
-		var form = $(formId);
-		form = form || document.forms[0];
-		Prado.Validation.ActiveTarget = form;
-		Prado.Validation.CurrentTargetGroup = null;
-		Prado.Validation.IsGroupValidation = false;
-		return Prado.Validation.IsValid(form);
-	}
-	return true;
-};
-	
-
-
-/**
- * Register Prado.Validation.Onload() for window.onload event.
- */
-Event.OnLoad(Prado.Validation.OnLoad);
\ No newline at end of file
diff --git a/framework/Web/Javascripts/prado/validation3.js b/framework/Web/Javascripts/prado/validation3.js
index 40472e7e..3ed31744 100644
--- a/framework/Web/Javascripts/prado/validation3.js
+++ b/framework/Web/Javascripts/prado/validation3.js
@@ -75,12 +75,13 @@ Object.extend(Prado.Validation,
 	 * then only validators belonging to that group will be validated.
 	 * @param string ID of the form to validate
 	 * @param string ID of the group to validate.
+	 * @param HTMLElement element that calls for validation
 	 */
-	validate : function(formID, groupID)
+	validate : function(formID, groupID, invoker)
 	{
 		if(this.managers[formID])
 		{
-			return this.managers[formID].validate(groupID);
+			return this.managers[formID].validate(groupID, invoker);
 		}
 		else
 		{
@@ -162,22 +163,24 @@ Prado.ValidationManager.prototype =
 	/**
 	 * Validate the validators managed by this validation manager.
 	 * @param string only validate validators belonging to a group (optional)
+	 * @param HTMLElement element that calls for validation
 	 * @return boolean true if all validators are valid, false otherwise.
 	 */
-	validate : function(group)
+	validate : function(group, invoker)
 	{
 		if(group)
-			return this._validateGroup(group);
+			return this._validateGroup(group, invoker);
 		else
-			return this._validateNonGroup();	
+			return this._validateNonGroup(invoker);	
 	},
 	
 	/**
 	 * Validate a particular group of validators.
 	 * @param string ID of the form 
+	 * @param HTMLElement element that calls for validation
 	 * @return boolean false if group is not valid, true otherwise.
 	 */
-	_validateGroup: function(groupID)
+	_validateGroup: function(groupID, invoker)
 	{
 		var valid = true;
 		if(this.groups.include(groupID))
@@ -185,7 +188,7 @@ Prado.ValidationManager.prototype =
 			this.validators.each(function(validator)
 			{
 				if(validator.group == groupID)
-					valid = valid & validator.validate();
+					valid = valid & validator.validate(invoker);
 				else
 					validator.hide();
 			});
@@ -197,14 +200,15 @@ Prado.ValidationManager.prototype =
 	/**
 	 * Validate validators that doesn't belong to any group.
 	 * @return boolean false if not valid, true otherwise.
+	 * @param HTMLElement element that calls for validation
 	 */
-	_validateNonGroup : function()
+	_validateNonGroup : function(invoker)
 	{
 		var valid = true;
 		this.validators.each(function(validator)
 		{
 			if(!validator.group)
-				valid = valid & validator.validate();
+				valid = valid & validator.validate(invoker);
 			else
 				validator.hide();
 		});
@@ -523,6 +527,7 @@ Prado.WebUI.TBaseValidator.prototype =
 	_isObserving : {},
 	group : null,
 	manager : null,
+	message : null,
 	
 	/**
 	 * <code>
@@ -543,10 +548,10 @@ Prado.WebUI.TBaseValidator.prototype =
 	 */
 	initialize : function(options)
 	{
-		options.OnValidate = options.OnValidate || Prototype.emptyFunction;
+	/*	options.OnValidate = options.OnValidate || Prototype.emptyFunction;
 		options.OnSuccess = options.OnSuccess || Prototype.emptyFunction;
 		options.OnError = options.OnError || Prototype.emptyFunction;
-		
+	*/	
 		this.options = options;
 		this.control = $(options.ControlToValidate);
 		this.message = $(options.ID);
@@ -617,21 +622,39 @@ Prado.WebUI.TBaseValidator.prototype =
 	/**
 	 * Calls evaluateIsValid() function to set the value of isValid property.
 	 * Triggers onValidate event and onSuccess or onError event.
+	 * @param HTMLElement element that calls for validation
 	 * @return boolean true if valid.
 	 */
-	validate : function()
+	validate : function(invoker)
 	{
+		if(typeof(this.options.OnValidate) == "function")
+			this.options.OnValidate(this, invoker);
+
 		if(this.enabled)
 			this.isValid = this.evaluateIsValid();
-		
-		this.options.OnValidate(this);
-		
-		this.updateControl();
-		
+				
 		if(this.isValid)
-			this.options.OnSuccess(this);
+		{
+			if(typeof(this.options.OnSuccess) == "function")
+			{
+				this.visible = true;
+				this.updateControlCssClass(this.control, this.isValid);	
+				this.options.OnSuccess(this, invoker);
+			}
+			else
+				this.updateControl();
+		}
 		else
-			this.options.OnError(this);
+		{
+			if(typeof(this.options.OnError) == "function")
+			{
+				this.visible = true;				
+				this.updateControlCssClass(this.control, this.isValid);
+				this.options.OnError(this, invoker);
+			}
+			else
+				this.updateControl();
+		}
 	
 		this.observeChanges(this.control);
 					
@@ -641,7 +664,7 @@ Prado.WebUI.TBaseValidator.prototype =
 	/**
 	 * Observe changes to the control input, re-validate upon change. If
 	 * the validator is not visible, no updates are propagated.
-	 * @param HTMLElement control to observe changes
+	 * @param HTMLElement element that calls for validation
 	 */
 	observeChanges : function(control)
 	{
@@ -667,9 +690,9 @@ Prado.WebUI.TBaseValidator.prototype =
 	},
 	
 	/**
-	 * @return string _trims the string value, empty string if value is not string.
+	 * @return string trims the string value, empty string if value is not string.
 	 */
-	_trim : function(value)
+	trim : function(value)
 	{
 		return typeof(value) == "string" ? value.trim() : "";
 	},
@@ -720,26 +743,25 @@ Prado.WebUI.TBaseValidator.prototype =
 	 	{
 	 		case 'TDatePicker':
 	 			if(control.type == "text")
-	 				return this._trim($F(control));
+	 				return this.trim($F(control));
 	 			else
 	 			{
-	 				this._observeDatePickerChanges();
+	 				this.observeDatePickerChanges();
 		
 	 				return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime();
 	 			}
 	 		default:
-	 			if(this._isListControlType())
-	 				return this._getFirstSelectedListValue();	 			
+	 			if(this.isListControlType())
+	 				return this.getFirstSelectedListValue();	 			
 	 			else
-		 			return this._trim($F(control));
+		 			return this.trim($F(control));
 	 	}
 	 },
 	 
 	 /**
 	  * Observe changes in the drop down list date picker, IE only.
-	  * @private
 	  */
-	 _observeDatePickerChanges : function()
+	 observeDatePickerChanges : function()
 	 {
 	 	if(Prado.Browser().ie)
 	 	{
@@ -754,13 +776,12 @@ Prado.WebUI.TBaseValidator.prototype =
 	 * Gets numeber selections and their values.
 	 * @return object returns selected values in <tt>values</tt> property
 	 * and number of selections in <tt>checks</tt> property.
-	 * @private
 	 */
-	_getSelectedValuesAndChecks : function(elements, initialValue)
+	getSelectedValuesAndChecks : function(elements, initialValue)
 	{
 		var checked = 0;
 		var values = [];
-		var isSelected = this._isCheckBoxType(elements[0]) ? 'checked' : 'selected';
+		var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
 		elements.each(function(element)
 		{
 			if(element[isSelected] && element.value != initialValue)
@@ -776,9 +797,8 @@ Prado.WebUI.TBaseValidator.prototype =
 	 * Gets an array of the list control item input elements, for TCheckBoxList
 	 * checkbox inputs are returned, for TListBox HTML option elements are returned.
 	 * @return array list control option elements.
-	 * @private
 	 */
-	_getListElements : function()
+	getListElements : function()
 	{
 		switch(this.options.ControlType)
 		{
@@ -787,7 +807,7 @@ Prado.WebUI.TBaseValidator.prototype =
 				for(var i = 0; i < this.options.TotalItems; i++)
 				{
 					var element = $(this.options.ControlToValidate+"_"+i);
-					if(this._isCheckBoxType(element))
+					if(this.isCheckBoxType(element))
 						elements.push(element);
 				}
 				return elements;
@@ -807,9 +827,8 @@ Prado.WebUI.TBaseValidator.prototype =
 	
 	/**
 	 * @return boolean true if element is of checkbox or radio type.
-	 * @private
 	 */
-	_isCheckBoxType : function(element)
+	isCheckBoxType : function(element)
 	{
 		if(element && element.type)
 		{
@@ -821,9 +840,8 @@ Prado.WebUI.TBaseValidator.prototype =
 	
 	/**
 	 * @return boolean true if control to validate is of some of the TListControl type.
-	 * @private
 	 */
-	_isListControlType : function()
+	isListControlType : function()
 	{
 		var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
 		return list.include(this.options.ControlType);
@@ -831,15 +849,14 @@ Prado.WebUI.TBaseValidator.prototype =
 	
 	/**
 	 * @return string gets the first selected list value, initial value if none found.
-	 * @private
 	 */
-	_getFirstSelectedListValue : function()
+	getFirstSelectedListValue : function()
 	{
 		var initial = "";
 		if(typeof(this.options.InitialValue) != "undefined")
 			initial = this.options.InitialValue;			
-		var elements = this._getListElements();		
-		var selection = this._getSelectedValuesAndChecks(elements, initial);
+		var elements = this.getListElements();		
+		var selection = this.getSelectedValuesAndChecks(elements, initial);
 		return selection.values.length > 0 ? selection.values[0] : initial;
 	}
 }
@@ -868,7 +885,7 @@ Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,
 	    else
 	    {
         	var a = this.getValidationValue();
-        	var b = this._trim(this.options.InitialValue);
+        	var b = this.trim(this.options.InitialValue);
         	return(a != b);
     	}
 	}
@@ -1105,13 +1122,13 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
 	 */
 	evaluateIsValid : function()
 	{
-		var elements = this._getListElements();
+		var elements = this.getListElements();
 		if(elements && elements.length <= 0)
 			return true;
 		
 		this.observeListElements(elements);
 		
-		var selection = this._getSelectedValuesAndChecks(elements);
+		var selection = this.getSelectedValuesAndChecks(elements);
 		return this.isValidList(selection.checks, selection.values);
 	},
 	
@@ -1120,7 +1137,7 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
 	 */
 	 observeListElements : function(elements)
 	 {
-		if(Prado.Browser().ie && this._isCheckBoxType(elements[0]))
+		if(Prado.Browser().ie && this.isCheckBoxType(elements[0]))
 		{
 			var validator = this;
 			elements.each(function(element)
@@ -1171,25 +1188,26 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
 	}
 });
 
-/**
- * TDataTypeValidator verifies if the input data is of the type specified
- * by <tt>DataType</tt> option.
- * The following data types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type.
- * - <b>String</b> A string data type.
- * For <b>Date</b> type, the option <tt>DateFormat</tt>
- * will be used to determine how to parse the date string. 
- */
-Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator,
-{
-	evaluateIsValid : function()
-	{
-		var value = this.getValidationValue();
-		if(value.length <= 0)
-			return true;
-		return this.convert(this.options.DataType, value) != null;
-	}
-});
+
+/** 
+ * TDataTypeValidator verifies if the input data is of the type specified 
+ * by <tt>DataType</tt> option. 
+ * The following data types are supported: 
+ * - <b>Integer</b> A 32-bit signed integer data type. 
+ * - <b>Float</b> A double-precision floating point number data type. 
+ * - <b>Date</b> A date data type. 
+ * - <b>String</b> A string data type. 
+ * For <b>Date</b> type, the option <tt>DateFormat</tt> 
+ * will be used to determine how to parse the date string.  
+ */ 
+Prado.WebUI.TDataTypeValidator = Class.extend(Prado.WebUI.TBaseValidator, 
+{ 
+        evaluateIsValid : function() 
+        { 
+                var value = this.getValidationValue(); 
+                if(value.length <= 0) 
+                        return true; 
+                return this.convert(this.options.DataType, value) != null; 
+        } 
+}); 
 
diff --git a/framework/Web/Javascripts/prado/validators.js b/framework/Web/Javascripts/prado/validators.js
deleted file mode 100644
index 5aa732b4..00000000
--- a/framework/Web/Javascripts/prado/validators.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/**
- * Validates that a given field has some input, 
- * @param ${parameter}
- * @return ${return}
- */
-Prado.Validation.TRequiredFieldValidator=function(){
-    var inputType = this.control.getAttribute("type");
-    if(inputType == 'file'){
-        return true;
-    }
-    else{
-        var a= Prado.Validation.trim($F(this.control));
-        var b= Prado.Validation.trim(this.attr.initialvalue);
-        return(a != b);
-    }
-}
-
-
-Prado.Validation.TRegularExpressionValidator = function()
-{
-	var value = Prado.Validation.trim($F(this.control));
-    if (value == "") return true;
-    var rx = new RegExp(this.attr.validationexpression);
-    var matches = rx.exec(value);
-    return (matches != null && value == matches[0]);
-}
-
-Prado.Validation.TEmailAddressValidator = Prado.Validation.TRegularExpressionValidator;
-
-Prado.Validation.TCustomValidator = function()
-{
-	var value = isNull(this.control) ? null : $F(this.control);
-    var func = this.attr.clientvalidationfunction;
-	eval("var validate = "+func);
-    return validate && isFunction(validate) ? validate(this, value) : true;
-}
-
-Prado.Validation.TRangeValidator = function()
-{
-	var value = Prado.Validation.trim($F(this.control));
-    if (value == "") return true;
-
-    var minval = this.attr.minimumvalue;
-    var maxval = this.attr.maximumvalue;
-
-	if (undef(minval) && undef(maxval))
-        return true;
-
-    if (minval == "") minval = 0;
-	if (maxval == "") maxval = 0;
-	
-	var dataType = this.attr.type;
-
-	if(undef(dataType))
-	    return (parseFloat(value) >= parseFloat(minval)) && (parseFloat(value) <= parseFloat(maxval));
-
-	//now do datatype range check.
-	var min = this.convert(dataType, minval);
-	var max = this.convert(dataType, maxval);
-	value = this.convert(dataType, value);	
-	return value >= min && value <= max;
-}
-
-Prado.Validation.TCompareValidator = function()
-{
-    var value = Prado.Validation.trim($F(this.control));
-    if (value.length == 0) return true;
-
-    var compareTo;
-
-    var comparee = $(this.attr.controlhookup);;
-
-	if(comparee)
-		compareTo = Prado.Validation.trim($F(comparee));
-	else
-	{
-		compareTo = isString(this.attr.valuetocompare) ? this.attr.valuetocompare : "";
-	}
-
-	var compare = Prado.Validation.TCompareValidator.compare;
-
-    var isValid =  compare.bind(this)(value, compareTo);
-
-	//update the comparee control css class name and add onchange event once.
-	if(comparee)
-	{
-		var className = this.attr.controlcssclass;
-		if(isString(className) && className.length>0)
-			Element.condClassName(comparee, className, !isValid);
-		if(undef(this.observingComparee))
-		{
-			Event.observe(comparee, "change", this.validate.bind(this));
-			this.observingComparee = true;
-		}
-	}
-	return isValid;
-}
-
-/**
- * Compare the two values, also performs data type check.
- * @param {string} value to compare with
- * @param {string} value to compare
- * @type {boolean} true if comparison or type check is valid, false otherwise.
- */
-Prado.Validation.TCompareValidator.compare = function(operand1, operand2)
-{
-	var op1, op2;
-	if ((op1 = this.convert(this.attr.type, operand1)) == null)
-		return false;
-	if (this.attr.operator == "DataTypeCheck")
-        return true;
-	if ((op2 = this.convert(this.attr.type, operand2)) == null)
-        return true;
-    switch (this.attr.operator) 
-	{
-        case "NotEqual":
-            return (op1 != op2);
-        case "GreaterThan":
-            return (op1 > op2);
-        case "GreaterThanEqual":
-            return (op1 >= op2);
-        case "LessThan":
-            return (op1 < op2);
-        case "LessThanEqual":
-            return (op1 <= op2);
-        default:
-            return (op1 == op2);
-    }
-}
-
-Prado.Validation.TRequiredListValidator = function()
-{
-	var min = undef(this.attr.min) ? Number.NEGATIVE_INFINITY : parseInt(this.attr.min);
-	var max = undef(this.attr.max) ? Number.POSITIVE_INFINITY : parseInt(this.attr.max);
-
-	var elements = document.getElementsByName(this.attr.selector);
-
-	if(elements.length <= 0)
-		return true;
-	
-	var required = new Array();
-	if(isString(this.attr.required) && this.attr.required.length > 0)
-		required = this.attr.required.split(/,\s* /);
-
-	var isValid = true;
-
-	var validator = Prado.Validation.TRequiredListValidator;
-
-	switch(elements[0].type)
-	{
-		case 'radio':
-		case 'checkbox':
-			isValid = validator.IsValidRadioList(elements, min, max, required);
-			break;
-		case 'select-multiple':
-			isValid = validator.IsValidSelectMultipleList(elements, min, max, required);
-			break;
-	}
-
-	var className = this.attr.elementcssclass;
-	if(isString(className) && className.length>0)
-		map(elements, function(element){ condClass(element, className, !isValid); });
-	if(undef(this.observingRequiredList))
-	{
-		Event.observe(elements, "change", this.validate.bind(this));
-		this.observingRequiredList = true;
-	}
-	return isValid;
-}
-
-//radio group selection
-Prado.Validation.TRequiredListValidator.IsValidRadioList = function(elements, min, max, required)
-{
-	var checked = 0;
-	var values = new Array();
-	for(var i = 0; i < elements.length; i++)
-	{
-		if(elements[i].checked)
-		{
-			checked++;
-			values.push(elements[i].value);
-		}
-	}
-	return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required);
-}
-
-//multiple selection check
-Prado.Validation.TRequiredListValidator.IsValidSelectMultipleList = function(elements, min, max, required)
-{
-	var checked = 0;
-	var values = new Array();
-	for(var i = 0; i < elements.length; i++)
-	{
-		var selection = elements[i];
-		for(var j = 0; j < selection.options.length; j++)
-		{
-			if(selection.options[j].selected)
-			{
-				checked++;
-				values.push(selection.options[j].value);
-			}
-		}
-	}
-	return Prado.Validation.TRequiredListValidator.IsValidList(checked, values, min, max, required);
-}
-
-//check if the list was valid
-Prado.Validation.TRequiredListValidator.IsValidList = function(checkes, values, min, max, required)
-{
-	var exists = true;
-
-	if(required.length > 0)
-	{
-		//required and the values must at least be have same lengths
-		if(values.length < required.length)
-			return false;
-		for(var k = 0; k < required.length; k++)
-			exists = exists && values.contains(required[k]);
-	}
-	
-	return exists && checkes >= min && checkes <= max;
-}
diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php
index adbc85ae..4ca4c1f6 100644
--- a/framework/Web/UI/WebControls/TBaseValidator.php
+++ b/framework/Web/UI/WebControls/TBaseValidator.php
@@ -41,6 +41,10 @@
  * and {@link setText Text} are empty, the body content of the validator will
  * be displayed. Error display is controlled by {@link setDisplay Display} property.
  *
+ * You can also customized the client-side behaviour by adding javascript
+ * code to the subproperties of the {@link getClientValidation ClientValidation}
+ * property.
+ *
  * You can also place a {@link TValidationSummary} control on a page to display error messages
  * from the validators together. In this case, only the {@link setErrorMessage ErrorMessage}
  * property of the validators will be displayed in the {@link TValidationSummary} control.
@@ -75,6 +79,8 @@ abstract class TBaseValidator extends TLabel implements IValidator
 	 * @var boolean whether the validator has been registered with the page
 	 */
 	private $_registered=false;
+	
+	private $_clientScript;
 
 	/**
 	 * Constructor.
@@ -145,8 +151,43 @@ abstract class TBaseValidator extends TLabel implements IValidator
 		$options['ControlToValidate'] = $control->getClientID();
 		$options['ControlCssClass'] = $this->getControlCssClass();
 		$options['ControlType'] = get_class($control);
+		
+		if(!is_null($this->_clientScript))
+			$options = array_merge($options,$this->_clientScript->getOptions());
+		
 		return $options;
 	}
+	
+	/**
+	 * Gets the TValidatorClientScript that allows modification of the client-
+	 * side validator events. 
+	 * 
+	 * The client-side validator supports the following events.
+	 * # <tt>OnValidate</tt> -- raised before client-side validation is
+	 * executed. 
+	 * # <tt>OnSuccess</tt> -- raised after client-side validation is completed
+	 * and is successfull, overrides default validator error messages updates.
+	 * # <tt>OnError</tt> -- raised after client-side validation is completed
+	 * and failed, overrides default validator error message updates.  
+	 * 
+	 * You can attach custom javascript code to each of these events
+	 * 
+	 * @return TValidatorClientScript javascript validator event options.
+	 */
+	public function getClientValidation()
+	{
+		if(is_null($this->_clientScript))
+			$this->_clientScript = $this->createClientScript();
+		return $this->_clientScript;
+	}
+	
+	/**
+	 * @return TValidatorClientScript javascript validator event options.
+	 */
+	protected function createClientScript()
+	{
+		return new TValidatorClientScript($this->getPage()->getClientScript());
+	}
 
 	/**
 	 * Renders the javascript code to the end script.
@@ -446,4 +487,74 @@ abstract class TBaseValidator extends TLabel implements IValidator
 			parent::renderContents($writer);
 	}
 }
+
+/**
+ * TValidatorClientScript class.
+ * 
+ * @todo Add doc to quickstart and classes.
+ * 
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $  $Date: $
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TValidatorClientScript extends TComponent
+{
+	private $_options;
+	private $_manager;
+	private $_effectsEnabled = false;
+	
+	public function __construct($manager)
+	{
+		$this->_options = new TMap;
+		$this->_manager = $manager;
+	}
+	
+	public function getOnValidate()
+	{
+		return $this->_options->itemAt['OnValidate'];	
+	}
+	
+	public function setOnValidate($javascript)
+	{
+		$this->_options->add('OnValidate', $this->ensureFunction($javascript));
+	}
+	
+	public function setOnSuccess($javascript)
+	{
+		$this->_options->add('OnSuccess', $this->ensureFunction($javascript));
+	}
+	
+	public function getOnSuccess()
+	{
+		return $this->_options->itemAt('OnSuccess');
+	}
+	
+	public function setOnError($javascript)
+	{
+		$this->_options->add('OnError', $this->ensureFunction($javascript));
+	}
+	
+	public function getOnError()
+	{
+		return $this->_options->itemAt('OnError');
+	}
+	
+	public function getOptions()
+	{
+		return $this->_options->toArray();
+	}
+	
+	private function ensureFunction($javascript)
+	{
+		if(TJavascript::isFunction($javascript))
+			return $javascript;
+		else
+		{
+			$code = "function(validator, invoker){ {$javascript} }";
+			return TJavascript::quoteFunction($code);
+		}
+	}
+}
+
 ?>
\ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TClientScript.php b/framework/Web/UI/WebControls/TClientScript.php
new file mode 100644
index 00000000..23aa1425
--- /dev/null
+++ b/framework/Web/UI/WebControls/TClientScript.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * TClientScript class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $  $Date: $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TClientScript class
+ *
+ * Allows importing of Prado Client Scripts from template via the 
+ * {@link setUsingPradoScripts UsingPradoScripts} property. Multiple Prado
+ * client-scripts can be specified using comma delimited string of the
+ * javascript library to include on the page. For example,
+ * 
+ * <code>
+ * <com:TClientScript UsingPradoScripts="effects, rico" />
+ * </code>
+ * 
+ * @TODO May be use it to include stylesheets as well.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $  $Date: $
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TClientScript extends TControl
+{
+	/**
+	 * @return string comma delimited list of javascript libraries to included
+	 * on the page.
+	 */
+	public function getUsingPradoScripts()
+	{
+		return $this->getViewState('PradoScripts', '');
+	}
+	
+	/**
+	 * Include javascript library to the current page. The current supported
+	 * libraries are: "prado", "effects", "ajax", "validator", "logger",
+	 * "datepicker", "rico", "colorpicker". Library dependencies are
+	 * automatically resolved.
+	 * 
+	 * @param string comma delimited list of javascript libraries to include.
+	 */
+	public function setUsingPradoScripts($value)
+	{
+		$this->setViewState('PradoScripts', $value, '');
+	}
+	
+	/**
+	 * Calls the client script manager to add each of the requested client
+	 * script libraries.
+	 * @param mixed event parameter
+	 */
+	public function onPreRender($param)
+	{
+		parent::onPreRender($param);
+		$scripts = preg_split('/,|\s+/', $this->getUsingPradoScripts());
+		$cs = $this->getPage()->getClientScript();
+		foreach($scripts as $script)
+		{
+			$script = trim($script);
+			if(strlen($script) > 0)
+				$cs->registerPradoScript($script);
+		}
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TLiteral.php b/framework/Web/UI/WebControls/TLiteral.php
index f335499f..60e4a6f6 100644
--- a/framework/Web/UI/WebControls/TLiteral.php
+++ b/framework/Web/UI/WebControls/TLiteral.php
@@ -80,7 +80,7 @@ class TLiteral extends TControl
 				$writer->write($text);
 		}
 		else
-			parent::renderContents($writer);
+			parent::render($writer);
 	}
 }
 
-- 
cgit v1.2.3