From 4aa1f46fcb508271b09cb5736d8bd0ef7206941d Mon Sep 17 00:00:00 2001 From: wei <> Date: Thu, 27 Apr 2006 08:39:55 +0000 Subject: Added client-side events to client-side validators. see tests/FunctionalTests/features/index.php?page=ValidatorEffects --- .gitattributes | 4 +- HISTORY | 4 + UPGRADE | 4 +- framework/Web/Javascripts/TJavaScript.php | 42 +- framework/Web/Javascripts/js/prado.js | 2 +- framework/Web/Javascripts/js/validator.js | 100 +-- framework/Web/Javascripts/prado/form.js | 2 +- framework/Web/Javascripts/prado/prado.js | 2 +- framework/Web/Javascripts/prado/validation.js | 767 --------------------- framework/Web/Javascripts/prado/validation3.js | 134 ++-- framework/Web/Javascripts/prado/validators.js | 222 ------ framework/Web/UI/WebControls/TBaseValidator.php | 111 +++ framework/Web/UI/WebControls/TClientScript.php | 75 ++ .../features/protected/controls/Layout.tpl | 5 + .../features/protected/pages/ValidatorEffects.page | 91 +++ 15 files changed, 443 insertions(+), 1122 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 create mode 100644 tests/FunctionalTests/features/protected/pages/ValidatorEffects.page diff --git a/.gitattributes b/.gitattributes index c8fb6ada..f70aa0e5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -710,9 +710,7 @@ framework/Web/Javascripts/prado/controls.js -text framework/Web/Javascripts/prado/element.js -text framework/Web/Javascripts/prado/form.js -text framework/Web/Javascripts/prado/prado.js -text -framework/Web/Javascripts/prado/validation.js -text framework/Web/Javascripts/prado/validation3.js -text -framework/Web/Javascripts/prado/validators.js -text framework/Web/Javascripts/prototype/AUTHORS -text framework/Web/Javascripts/prototype/LICENSE -text framework/Web/Javascripts/prototype/README -text @@ -771,6 +769,7 @@ framework/Web/UI/WebControls/TButtonColumn.php -text framework/Web/UI/WebControls/TCheckBox.php -text framework/Web/UI/WebControls/TCheckBoxColumn.php -text framework/Web/UI/WebControls/TCheckBoxList.php -text +framework/Web/UI/WebControls/TClientScript.php -text framework/Web/UI/WebControls/TColorPicker.php -text framework/Web/UI/WebControls/TCompareValidator.php -text framework/Web/UI/WebControls/TContent.php -text @@ -859,6 +858,7 @@ tests/FunctionalTests/features/protected/pages/I18N/Home.page -text tests/FunctionalTests/features/protected/pages/I18N/Home.zh_CN.page -text tests/FunctionalTests/features/protected/pages/I18N/config.xml -text tests/FunctionalTests/features/protected/pages/RatingList.page -text +tests/FunctionalTests/features/protected/pages/ValidatorEffects.page -text tests/FunctionalTests/index.php -text tests/FunctionalTests/quickstart.php -text tests/FunctionalTests/quickstart/Advanced/I18N.php -text diff --git a/HISTORY b/HISTORY index 1d9430ed..cd9c8482 100644 --- a/HISTORY +++ b/HISTORY @@ -16,12 +16,16 @@ ENH: TButtonColumn can now be a column of image buttons (Qiang) ENH: TLiteral will display body content if Text is empty (Qiang) ENH: Format string in classes extending TDataGridColumn can now evaluate an expression (Qiang) ENH: Format string in classes extending TListControl can now evaluate an expression (Qiang) +ENH: Custom visual effects can be added to client-side validators. (Wei) +ENH: TJavascript::encode() allows raw javascript code when string begins with "javascript:" (Wei) CHG: Rewrote client-side javascript validators, check your client-side validation behaviour (Wei) CHG: Updated the javascript Prototype library, a few utilties functions REMOVED, may break your existing javascript code. (Wei) CHG: Build javascript without compression, only comments are removed. (Wei) CHG: TDatePicker's date can be set using Date property, it value must be in same format as DateFormat, TimeStamp must be set as integer (wei) CHG: TSimpleDateFormatter::parse() now return an integer or null on parse error (Wei) NEW: TListControlValidator (Wei) +NEW: TClientScript (Wei) + Version 3.0RC2 April 16, 2006 diff --git a/UPGRADE b/UPGRADE index 20c91cc9..ccf8c289 100644 --- a/UPGRADE +++ b/UPGRADE @@ -16,7 +16,9 @@ for both A and B. Upgrading from v3.0.0 RC2 ------------------------- -There should be no compatibility issues. +There should be no PHP compatibility issues. Javascript libraries +were updated and client-side validators rewritten. + Upgrading from v3.0.0 RC1 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 javascript: + */ + 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'} * - * - * To pass raw javascript statements start strings with - * javascript:. E.g. - * - * $options['onLoading'] = "javascript:function(){ alert('hello'); }"; - * //outputs {'onLoading':function(){ alert('hello'); }} - * * - * 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 javascript: 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..9e01fe42 100644 --- a/framework/Web/Javascripts/js/prado.js +++ b/framework/Web/Javascripts/js/prado.js @@ -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..a68fbfa1 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(this.enabled) this.isValid = this.evaluateIsValid(); -this.options.OnValidate(this); -this.updateControl(); +if(typeof(this.options.OnValidate) == "function") +this.options.OnValidate(this, invoker); 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.options.OnError(this); +this.updateControl(); +} +else +{ +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,3 @@ 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; -} -}); 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..d75c3dda 100644 --- a/framework/Web/Javascripts/prado/prado.js +++ b/framework/Web/Javascripts/prado/prado.js @@ -1,7 +1,7 @@ var Prado = { - Version: '3.0a', + Version: '3.0', /** * Returns browser information. Example 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. Internationalization - * is not supported - * @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. - * The currency input format is very strict, null will be returned if - * the pattern does not match. - * @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 - * new Prado.Validation(Prado.Validation.RequiredFieldValidator, options); - * or to use the CustomValidator, - * new Prado.Validation(Prado.Validation.CustomValidator, options); - */ -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 : "
", first : "", pre : "", post : "
", last : ""}; - case "SingleParagraph": - return { header : " ", first : "", pre : "", post : " ", last : "
"}; - case "BulletList": - default: - return { header : "", first : ""}; - } - }, - - /** - * 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..615200dc 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, /** * @@ -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 values property * and number of selections in checks 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,6 @@ Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator, } }); -/** - * TDataTypeValidator verifies if the input data is of the type specified - * by DataType option. - * The following data types are supported: - * - Integer A 32-bit signed integer data type. - * - Float A double-precision floating point number data type. - * - Date A date data type. - * - String A string data type. - * For Date type, the option DateFormat - * 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. + * # OnValidate -- raised before client-side validation is + * executed. + * # OnSuccess -- raised after client-side validation is completed + * and is successfull, overrides default validator error messages updates. + * # OnError -- 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 + * @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 @@ + + * @link http://www.pradosoft.com/ + * @copyright Copyright © 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, + * + * + * + * + * + * @TODO May be use it to include stylesheets as well. + * + * @author Wei Zhuo + * @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/tests/FunctionalTests/features/protected/controls/Layout.tpl b/tests/FunctionalTests/features/protected/controls/Layout.tpl index 18482377..66b42f6c 100644 --- a/tests/FunctionalTests/features/protected/controls/Layout.tpl +++ b/tests/FunctionalTests/features/protected/controls/Layout.tpl @@ -16,6 +16,11 @@ margin-top: 2em; display: block; } + .required + { + border:1px solid red; + background-color: #fdd; + } /*]]>*/ diff --git a/tests/FunctionalTests/features/protected/pages/ValidatorEffects.page b/tests/FunctionalTests/features/protected/pages/ValidatorEffects.page new file mode 100644 index 00000000..47d99969 --- /dev/null +++ b/tests/FunctionalTests/features/protected/pages/ValidatorEffects.page @@ -0,0 +1,91 @@ + + +

Validator Visual Effects Test

+
+ Create New Account + + + +
+ Username: + + + + Effect.Shake(validator.control); + Effect.Appear(validator.message); + + + Effect.Fade(validator.message); + + +
+
+ Password + + + +
+
+ +
+ +
+ + +
+ Sign In + +
+ Login Name: + + + +
+ +
+ Password: + + +
+ + + + +
+ +
+ +
+ + +
\ No newline at end of file -- cgit v1.2.3